import { defineStore } from "pinia";
import { getNotificationHistory } from "@/api/notification";
import { ref, computed } from "vue";
import { ElMessage, ElNotification, ElMessageBox } from "element-plus";
import { eventEngine } from "@/services/eventEngine";
import { EventType, type ServerSentEvent } from "@/types/sse.types";
import {
  NotificationLevel,
  getTopicNameCN,
  type NotificationSchema,
  type NotificationHistory,
  NotificationTopic
} from "@/types/notification.types";
import type { HttpResponse } from "types/request";

export const useNotificationStore = defineStore("notification", () => {
  // State
  const notifications = ref<NotificationSchema[]>([]);
  const isLoadingHistory = ref<boolean>(false);
  const isInitialized = ref<boolean>(false);
  const error = ref<string | null>(null);
  const cachedEvents = ref<ServerSentEvent[]>([]);
  const pollingInterval = ref<number | null>(null);

  // Constants
  const MAX_CACHE_SIZE = 100;
  const POLLING_INTERVAL_MS = 10000; // 10 seconds

  // Getters
  const unreadCount = computed(() => {
    return notifications.value.filter(notification => !notification.isRead)
      .length;
  });

  // Group notifications by type for the UI
  const groupedNotifications = computed(() => {
    // Create a map to group notifications by topic
    const groupsMap = new Map();

    // init groupsMap with NotificationTopic enum
    Object.values(NotificationTopic).forEach(topic => {
      groupsMap.set(topic, {
        key: topic,
        name: getTopicNameCN(topic),
        list: [],
        emptyText: "暂无通知"
      });
    });

    notifications.value.forEach(notification => {
      // Map notification level to Element-plus status
      let status: "primary" | "success" | "warning" | "info" | "danger" =
        "info";
      let extra: string = "";

      switch (notification.level) {
        case NotificationLevel.INFO:
          status = "success";
          extra = notification.extra || "INFO";
          break;
        case NotificationLevel.IMPORTANT:
          status = "primary";
          extra = notification.extra || "IMPORTANT";
          break;
        case NotificationLevel.WARNING:
          status = "warning";
          extra = notification.extra || "WARNING";
          break;
        case NotificationLevel.CRITICAL:
          status = "danger";
          extra = notification.extra || "CRITICAL";
          break;
      }

      const group = groupsMap.get(notification.topic);
      group.list.push({
        avatar: "", // No avatar for system notifications
        title: notification.title,
        datetime: new Date(notification.msg_datetime).toLocaleString(),
        type: "1",
        description: notification.content,
        status,
        extra,
        id: notification.id,
        isRead: notification.isRead
      });
    });

    // Convert the map to an array
    const groupsArray = Array.from(groupsMap.values());

    // Sort the array based on the order of NotificationTopic enum
    return groupsArray.sort((a, b) => {
      // Get the enum values in order
      const topicOrder = Object.values(NotificationTopic);
      // Find the index of each topic in the enum
      const indexA = topicOrder.indexOf(a.key);
      const indexB = topicOrder.indexOf(b.key);
      // Sort by index
      return indexA - indexB;
    });
  });

  // Register events
  eventEngine.on(EventType.NOTIFICATION, handleNotificationEvent);
  console.log("Notification store registered event handlers");

  // Actions
  /**
   * Initialize the notification store and register with the EventEngine
   */
  async function init() {
    // Only initialize if not already initialized or loading
    if (isLoadingHistory.value || isInitialized.value) {
      console.log(
        "Notification store is already loading/initialized, skip init"
      );
      return;
    }

    try {
      // Fetch initial data
      await fetchHistoryNotifications(true);
      console.log("Notification store initialized successfully");

      // Start polling after successful initialization
      startPolling();
    } catch (err) {
      console.error(`通知数据初始化失败：${err}`);
      ElMessage.error(`通知数据初始化失败，准备重试！`);

      // Schedule retry
      setTimeout(init, 5000);

      // Re-throw the error to be handled by the caller
      throw err;
    }
  }

  /**
   * Start polling for notifications
   */
  function startPolling() {
    if (pollingInterval.value === null) {
      console.log(
        `Starting notification polling (every ${POLLING_INTERVAL_MS / 1000}s)`
      );
      pollingInterval.value = window.setInterval(() => {
        fetchHistoryNotifications(false).catch(err => {
          console.error("Error during notification polling:", err);
        });
      }, POLLING_INTERVAL_MS);
    }
  }

  /**
   * Stop polling for notifications
   */
  function stopPolling() {
    if (pollingInterval.value !== null) {
      console.log("Stopping notification polling");
      window.clearInterval(pollingInterval.value);
      pollingInterval.value = null;
    }
  }

  /**
   * Fetch historical notifications from the API
   * @param isInitialLoad Whether this is the initial load (affects read status)
   */
  async function fetchHistoryNotifications(isInitialLoad = false) {
    if (isLoadingHistory.value) {
      return; // Prevent concurrent requests
    }

    isLoadingHistory.value = true;
    error.value = null;

    try {
      const response = await getNotificationHistory();
      const httpResponse = response as HttpResponse<NotificationHistory>;

      if (httpResponse.success && httpResponse.data) {
        const { history } = httpResponse.data;

        if (isInitialLoad) {
          // Initial load - set all notifications as read
          notifications.value = history.map(notification => ({
            ...notification,
            isRead: true
          }));
          isInitialized.value = true;

          // Process any cached events
          processCachedEvents();
        } else {
          // Polling update - compare with existing notifications and add new ones
          const existingIds = new Set(notifications.value.map(n => n.id));
          const newNotifications = history.filter(n => !existingIds.has(n.id));

          if (newNotifications.length > 0) {
            console.log(
              `Found ${newNotifications.length} new notifications during polling`
            );
            // Add new notifications and mark them as unread
            const newNotificationsWithReadStatus = newNotifications.map(
              notification => ({
                ...notification,
                isRead: false
              })
            );

            // Add to the beginning of the array
            notifications.value = [
              ...newNotificationsWithReadStatus,
              ...notifications.value
            ];

            // Display notification popups for new notifications
            newNotificationsWithReadStatus.forEach(notification => {
              displayNotificationPopup(notification);
            });
          }
        }
      } else {
        throw new Error(
          httpResponse.message || "Failed to fetch notification history"
        );
      }
    } catch (err) {
      error.value = err.message || "Unknown error";
      console.error("Failed to fetch notification history:", err);
      if (isInitialLoad) {
        ElMessage.error("获取通知历史记录失败");
      }
    } finally {
      isLoadingHistory.value = false;
    }
  }

  /**
   * Handle notification events from the EventEngine
   */
  function handleNotificationEvent(event: ServerSentEvent) {
    // If not initialized or loading is in progress, cache the event
    if (!isInitialized.value || isLoadingHistory.value) {
      console.log(
        `Caching notification event until initialized: ${event.event_id}`
      );
      cacheEvent(event);
      return;
    }

    // Process the notification
    try {
      if (event.data && typeof event.data === "object") {
        const notification = event.data as NotificationSchema;

        // Check if we already have this notification
        const exists = notifications.value.some(n => n.id === notification.id);

        if (!exists) {
          // Add the notification to the store
          handleNewNotification(notification);

          // Display a popup notification based on level
          displayNotificationPopup(notification);
        }
      }
    } catch (err) {
      console.error(
        `Error processing notification event ${event.event_id}:`,
        err
      );
    }
  }

  /**
   * Add an event to the cache with size limit enforcement
   */
  function cacheEvent(event: ServerSentEvent): void {
    cachedEvents.value.push(event);

    // If cache exceeds size limit, remove oldest events
    if (cachedEvents.value.length > MAX_CACHE_SIZE) {
      cachedEvents.value = cachedEvents.value.slice(-MAX_CACHE_SIZE);
    }
  }

  /**
   * Process cached events after initialization
   */
  function processCachedEvents(): void {
    if (cachedEvents.value.length === 0) {
      return;
    }

    console.log(
      `Processing ${cachedEvents.value.length} cached notification events`
    );

    // Sort events by event_id to ensure they're processed in order
    cachedEvents.value.sort((a, b) => {
      return a.event_id.localeCompare(b.event_id);
    });

    // Process each event
    for (const event of cachedEvents.value) {
      if (event.event_type === EventType.NOTIFICATION) {
        handleNotificationEvent(event);
      }
    }

    // Clear the cache
    cachedEvents.value = [];
  }

  /**
   * Handle a new notification
   */
  function handleNewNotification(notification: NotificationSchema): void {
    // Add the read status
    const notificationWithReadStatus = {
      ...notification,
      isRead: false
    };

    // Add to the notifications array (no sorting, just add to the beginning)
    notifications.value = [notificationWithReadStatus, ...notifications.value];
  }

  /**
   * Display a popup notification based on notification level
   */
  function displayNotificationPopup(notification: NotificationSchema): void {
    // Only display popups for notifications
    switch (notification.level) {
      case NotificationLevel.INFO:
        ElNotification({
          title: notification.title,
          message: notification.content,
          type: "info",
          duration: 2000 // Auto-closes after 1.5 seconds
        });
        break;

      case NotificationLevel.IMPORTANT:
        ElNotification({
          title: notification.title,
          message: notification.content,
          type: "warning",
          duration: 5000 // Auto-closes after 3 seconds
        });
        break;

      case NotificationLevel.WARNING:
        ElNotification({
          title: notification.title,
          message: notification.content,
          type: "warning",
          duration: 0 // Doesn't auto-close
        });
        break;

      case NotificationLevel.CRITICAL:
        // Use message box for critical notifications
        ElMessageBox.alert(notification.content, notification.title, {
          confirmButtonText: "确认",
          type: "error",
          callback: () => markAsRead(notification.id)
        });
        break;
    }
  }

  /**
   * Mark a notification as read
   */
  function markAsRead(notificationId: string): void {
    const index = notifications.value.findIndex(n => n.id === notificationId);
    if (index !== -1) {
      notifications.value[index] = {
        ...notifications.value[index],
        isRead: true
      };
    }
  }

  /**
   * Mark all notifications as read
   */
  function markAllAsRead(): void {
    notifications.value = notifications.value.map(notification => ({
      ...notification,
      isRead: true
    }));
  }

  /**
   * Clean up resources when component is unmounted
   */
  function dispose(): void {
    // Stop polling
    stopPolling();
    // Remove event listener
    eventEngine.off(EventType.NOTIFICATION, handleNotificationEvent);
  }

  return {
    // State
    notifications,
    isLoadingHistory,
    error,

    // Getters
    unreadCount,
    groupedNotifications,

    // Actions
    init,
    markAsRead,
    markAllAsRead,
    dispose
  };
});
